package com.google.code.server4j.connector.bio;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingQueue;
import com.google.code.server4j.connector.Connector;
import com.google.code.server4j.connector.ProcessAdapter;
import com.google.code.server4j.util.BaseLifeCycle;
import com.google.code.server4j.util.Log;

public class BioConnector extends BaseLifeCycle implements Connector {

	
	private ServerSocket ssocket;
	
	private LinkedBlockingQueue<Socket> queue = new LinkedBlockingQueue<Socket>();
	
	private Acceptor acceptor;
	private Worker worker;
	private int port;
	private ProcessAdapter adapter;
	
	public void setPort(int port) {
		this.port = port;
	}

	public void setProcessAdapter(ProcessAdapter adapter) {
		this.adapter = adapter;
	}

	public void doInit() throws Exception {
		ssocket = new ServerSocket(port);
		acceptor = new Acceptor();
		super.doInit();
	}
	
	public void doStart()throws Exception {
		Thread acceptorThread = new Thread(acceptor,"acceptor");
		worker = new Worker();
		Thread workerThread = new Thread(worker,"worker");
		acceptorThread.start();
		workerThread.start();
		super.doStart();
	}
	
	private class Acceptor implements Runnable {

		private volatile boolean isRun = true;
		
		public void run() {
			while(isRun) {
				try {
					Socket socket = ssocket.accept();
					Log.debug("accept socket : "+socket);
					queue.offer(socket);
				} catch (IOException e) {
					Log.error("acceptor thread error", e);
				}
			}
			
		}
		
		public void close() {
			isRun = false;
		}
	}
	

	
	private class Worker implements Runnable {

		private volatile boolean isRun = true;
		
		@Override
		public void run() {
			while(isRun) {
				try {
					Socket socket = queue.take();
					boolean isOk = adapter.process(socket);
					if(!isOk) {
						socket.close();
					}
					
				} catch (IOException e) {
					Log.error(e.getMessage(), e);
				} catch (InterruptedException e) {
					Log.error(e.getMessage(), e);
				}
			}
		}
		
		public void close() {
			isRun = false;
		}
	}
	
	public void doStop()throws Exception {
		if(acceptor != null) {
			acceptor.close();
		}
		if(worker != null) {
			worker.close();
		}
		Socket socket = new Socket("localhost", port);
		socket.getOutputStream().write("GET / HTTP/1.1".getBytes());
		super.doStop();
		
	}

	
}
